#pragma once

#include "Connection.hpp"
#include "Reactor.hpp"
#include "Protocol.hpp"


class Handler
{
    const static int buffer_size = 1024;

    static void Handle(Connection *conn)
    {
        std::string &msg = conn->GetInbuffer();
        Protocol ptl;
        std::string req = ptl.DeCode(msg);
        while(req.size())
        {
            // 得到一个完整报文
            std::cout << "req: "<< req << std::endl;
            // 1. 对请求报文进行反序列化
            Calculate *cal = ptl.ReqDeSerialization(req);
            // 2. 业务处理
            cal->Cal();
            // 3. 对响应信息进行序列化
            std::string resp = ptl.ResSerialization(cal);
            // 4. 将响应放入输出缓冲区
            conn->SetOutBuffer(resp);

            delete cal;
            // 获取下一个报文
            req = ptl.DeCode(msg);
        }
        Sender(conn);
    }
public:

    static void Recver(Connection *conn)
    {
        errno = 0;
        int fd = conn->Sockfd();
        char buffer[buffer_size];
        while(true)
        {
            int n = recv(fd, buffer, sizeof(buffer) - 1, 0);
            if(n > 0)
            {
                buffer[n] = '\0';
                conn->SetInBuffer(std::string(buffer));
            }
            else
            {
                if(errno == EAGAIN) break;
                else if(errno == EINTR) continue;
                else
                {
                    ELOG("recv error");
                    Excepter(conn);
                    return;
                }
            }
        }
        Handle(conn);
    }
    static void Sender(Connection *conn)
    {
        int fd = conn->Sockfd();
        std::string &msg = conn->GetOutbuffer();
        while(true)
        {
            int n = send(fd, msg.c_str(), msg.size(), 0);
            if(n > 0)
            {
                msg.erase(0, n);
            }
            else
            {
                if(errno == EAGAIN) break;
                else if(errno == EINTR) continue;
                else
                {
                    ELOG("sender error ...");
                    Excepter(conn);
                    return;
                }
            }
        }
        if(msg.size())
        {
            conn->_R->SetEvents(conn->Sockfd(), true, true);
        }
        else
        {
            conn->_R->SetEvents(conn->Sockfd(), true, false);
        }
    }
    static void Excepter(Connection *conn)
    {
        ILOG("fd: %d error, close fd", conn->Sockfd());
        conn->_R->DelConnection(conn);
    }
};